package com.zebra.gateway;

import cn.hutool.core.util.RandomUtil;
import com.zebra.gateway.processor.GatewayProcessorUtil;
import com.zebra.remoting.config.GatewayServerInfo;
import com.zebra.common.OnlineType;
import com.zebra.remoting.connection.Connection;
import com.zebra.remoting.protocol.CommandProfile;

import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.CopyOnWriteArrayList;
import java.util.stream.Collectors;

public class GwConfigInfoManager {

    private static GwConfigInfoManager configInfoManager = new GwConfigInfoManager();

    private GatewayServerInfo serverInfo;

    /* 多个注册中心 */
    private  CopyOnWriteArrayList<Connection> registers = new CopyOnWriteArrayList();

    /* key: serverId,  对应多个connection */
    private ConcurrentHashMap<Integer, CopyOnWriteArrayList<Connection>> tmsServers = new ConcurrentHashMap(4);

    /*key cmd,  V: CommandModel */
    private ConcurrentHashMap<Integer, CommandProfile> cmds = new ConcurrentHashMap();

    private String registerAddr;

    private GwConfigInfoManager(){
    }

    public static GwConfigInfoManager getInstance() {
        return configInfoManager;
    }

    // set serverInfo
    public GatewayServerInfo getGwServerInfo() {
        return serverInfo;
    }

    public void setGwServerInfo(GatewayServerInfo serverInfo) {
        this.serverInfo = serverInfo;
    }

    public void setGwServerId(int serverId){
        this.serverInfo.setServerId(serverId);
        this.serverInfo.setOnline(OnlineType.Online.value());
    }


    //---register  ------RA----------
    public void registerRA(Connection connection){
        registers.add(connection);
    }

    public Connection getRAConnection(){
        List<Connection> registerList = registers.stream().filter(Connection::isFine).collect(Collectors.toList());
        int size = registerList.size();
        return size == 0 ? null : size == 1 ? registerList.get(0) : registerList.get(RandomUtil.randomInt(0, size));
    }

    public long getRaSize(){
        return registers.stream().filter(Connection::isFine).count();
    }

    public List<Connection> findRAALL(){
        return registers.stream().filter(Connection::isFine).collect(Collectors.toList());
    }

    public void removeRa(Connection connection){
        this.registers.remove(connection);
    }

    //-------------- TMS---------
    public void registerTMS(Connection connection){
        CopyOnWriteArrayList<Connection> list = tmsServers.get(connection.getServerId());
        if (null == list){
            list = new CopyOnWriteArrayList();
            list.add(connection);
            tmsServers.put(connection.getServerId(), list);
            return;
        }
        list.add(connection);
    }

    public Connection getTMSConnection(int serverId, long userId){
        List<Connection> list = findTmsList(serverId);
        if (null == list){
            return null;
        }
        int index = (int) (userId % list.size());
        return list.get(index);
    }

    public Connection getTMSConnectionByRandom(int serverId){
        List<Connection> list = findTmsList(serverId);
        if (null == list){
            return null;
        }
        return list.get(RandomUtil.randomInt(0, list.size()));
    }

    public int getTmsSize(int serverId){
        List<Connection> list = findTmsList(serverId);
        return null == list || list.isEmpty() ? 0 : list.size();
    }

    private List<Connection> findTmsList(int serverId){
        CopyOnWriteArrayList<Connection> list = tmsServers.get(serverId);
        if (null == list || list.isEmpty()){
            return null;
        }
        List<Connection>  connectionList = list.stream().filter(Connection::isFine).collect(Collectors.toList());
        if (null == connectionList || connectionList.isEmpty()){
            tmsServers.remove(serverId);
        }
        return connectionList;
    }

    public String buildLinkTms(){
        if (tmsServers.isEmpty() && registers.isEmpty()){
            return "AT";
        }

        int size = (tmsServers.size() * 8) + (registers.size() * 8) + 5;
        StringBuilder stringBuilder = new StringBuilder(size);
        if (!tmsServers.isEmpty()){
            Map<Integer, Integer> tmsMap = new HashMap<>(tmsServers.size());
            tmsServers.forEach((k, v) -> tmsMap.put(k, getTmsSize(k)));
            tmsMap.forEach((k, v) -> stringBuilder.append(k).append('-').append(v).append(", "));
        }
        stringBuilder.append("AT ");
        if (!registers.isEmpty()){
            registers.forEach(c -> {
                if (c.isFine()){
                    stringBuilder.append(c.getServerId()).append("-1, ");
                }
            });
        }
        serverInfo.setLinkTms(stringBuilder.toString());
        return serverInfo.getLinkTms();
    }

    public void removeTmsConnection(Connection connection) throws Exception {
        int sid = connection.getServerId();
        if (null == tmsServers.get(sid) || tmsServers.get(sid).isEmpty()){
            return;
        }
        tmsServers.get(sid).remove(connection);
        if (tmsServers.get(sid).isEmpty()){
            tmsServers.remove(sid);
            GatewayProcessorUtil.printLog();
            GatewayProcessorUtil.sendLinksToRA();
        }
    }

    //------------CMD----------------
    public void registerCMDS(List<CommandProfile> commandProfiles){
        commandProfiles.forEach(c -> cmds.put(c.getCmd(), c));
    }

    public CommandProfile getCmdByCmd(int cmd){
        return cmds.get(cmd);
    }

    public Set<Integer> findCmds(){
        return cmds.keySet();
    }

    //----------RegisterAddr----------
    public String getRegisterAddr() {
        return registerAddr;
    }

    public void setRegisterAddr(String registerAddr) {
        this.registerAddr = registerAddr;
    }
}
